/* $RCSFile: DBResourceExpressionBuilder.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.ExternalResourceProvider/DBResourceExpressionBuilder.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:30  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Web.Compilation;
using System.Globalization;
using System.ComponentModel;
using System.Web.UI;
using System.CodeDom;
using System.Web;
using System.Threading;
using System.Diagnostics;
using ADNCRM.CustomResourceProviders;


namespace ADNCRM.CustomResourceProviders.DBResourceProvider
{
    /// <summary>
    /// Custom expression builder support for $Resources expressions.
    /// </summary>
    public class DBResourceExpressionBuilder : ExpressionBuilder
    {
        private static ResourceProviderFactory s_resourceProviderFactory;
        public const string DefaultClassKey    =   "ADNCRM";

        public DBResourceExpressionBuilder()
        {
            if ( ResourceTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine("[V]DBResourceExpressionBuilder Ctor CALLED.",ResourceTraceSwitch.Sw.Info);

        }

        public static object GetGlobalResourceObjectEx(string classKey, string resourceKey,string DefaultValue)
        {
            if ( ResourceTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder GetGlobalResourceObjectEx ({0}, {1}, {2})", classKey, resourceKey,DefaultValue),ResourceTraceSwitch.Sw.Info);

            object res                          =   null;
            try
            {
                res                             =   DBResourceExpressionBuilder.GetGlobalResourceObject(classKey, resourceKey, null);
            }
            catch(Exception ex)
            {
                if ( ResourceTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder GetGlobalResourceObjectEx cached DefaultValue: {0}, ex: {1}", DefaultValue,ex),ResourceTraceSwitch.Sw.Info);
                if ( DefaultValue == string.Empty )
                    throw;
            }
            if (res == null)
            {
                // if no default key, throw
                if ( DefaultValue == string.Empty )
                    throw new ArgumentException(String.Format(Thread.CurrentThread.CurrentUICulture, Properties.Resources.RM_ResourceNotFound, resourceKey));
            }

            if ( res == null )
                return DefaultValue;
            if (( res is string ) && (((string)res) == string.Empty ))
                return DefaultValue;
            return res;
        }

        public static object GetGlobalResourceObject(string classKey, string resourceKey)
        {
            if ( ResourceTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder GetGlobalResourceObject({0}, {1})", classKey, resourceKey),ResourceTraceSwitch.Sw.Info);

            return DBResourceExpressionBuilder.GetGlobalResourceObject(classKey, resourceKey, null);
        }

        public static object GetGlobalResourceObject(string classKey, string resourceKey, CultureInfo culture)
        {
            if ( ResourceTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder GetGlobalResourceObject BEG classKey: {0}, resourceKey: {1}, culture: {2}", classKey, resourceKey, (culture==null) ? string.Empty:culture.ToString()),ResourceTraceSwitch.Sw.Info);

            DBResourceExpressionBuilder.EnsureResourceProviderFactory();
            IResourceProvider provider  =   DBResourceExpressionBuilder.s_resourceProviderFactory.CreateGlobalResourceProvider(classKey);
            object result               =   provider.GetObject(resourceKey, culture);
            if ( ResourceTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder GetGlobalResourceObject END result='{0}'", (result==null) ? string.Empty:result.ToString()),ResourceTraceSwitch.Sw.Info);
            return result;
        }

        public override object EvaluateExpression(object target, BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
        {
            if ( ResourceTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder EvaluateExpression BEG target: {0}, entry.ControlID: {1}, parsedData: {2}", target, entry.ControlID, parsedData),ResourceTraceSwitch.Sw.Info);

            DBResourceExpressionFields fields     =   parsedData as DBResourceExpressionFields;

            DBResourceExpressionBuilder.EnsureResourceProviderFactory();
            IResourceProvider provider                  =   DBResourceExpressionBuilder.s_resourceProviderFactory.CreateGlobalResourceProvider(fields.ClassKey);
            try
            {
                object ob                               =   provider.GetObject(fields.ResourceKey,null);
                if ( ResourceTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder EvaluateExpression After GetObject object: {0}", (ob==null) ? "null":ob.ToString()),ResourceTraceSwitch.Sw.Info);
                if ( ( ob == null ) || ( ob.Equals(string.Empty) && !fields.DefaultKey.Equals(string.Empty) ) )
                {
                    if ( ResourceTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder EvaluateExpression using defaultKey target: {0}, entry.ControlID: {1}, defaultKey: {2}", target, entry.ControlID, fields.DefaultKey),ResourceTraceSwitch.Sw.Info);
                    ob                                  =   fields.DefaultKey;
                }
                return ob;
            }
            catch ( Exception ex )
            {
                if ( ResourceTraceSwitch.Sw.TraceError )
                    Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[E]DBResourceExpressionBuilder EvaluateExpression  ResourceKey: {0}, ex: {1}", fields.ResourceKey,ex),ResourceTraceSwitch.Sw.Info);
                // If no default we throw an Exception
                if ( fields.DefaultKey == string.Empty )
                    throw new ArgumentException(String.Format(Thread.CurrentThread.CurrentUICulture, Properties.Resources.RM_ResourceNotFound, fields.ResourceKey));
            }
            if ( ResourceTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder EvaluateExpression afetre ex target: {0}, entry.ControlID: {1}, defaultKey: {2}", target, entry.ControlID, fields.DefaultKey),ResourceTraceSwitch.Sw.Info);
            return fields.DefaultKey;
        }

        public override System.CodeDom.CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
        {
            if ( ResourceTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder BEG GetCodeExpression({0}, {1}, {2})", entry, parsedData, context),ResourceTraceSwitch.Sw.Info);

            DBResourceExpressionFields fields     =   parsedData as DBResourceExpressionFields;
            CodeMethodInvokeExpression exp        =   null;
            if ( !string.IsNullOrEmpty(fields.DefaultKey ))
                    exp =   new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(typeof(DBResourceExpressionBuilder)), "GetGlobalResourceObjectEx", new CodePrimitiveExpression(fields.ClassKey), new CodePrimitiveExpression(fields.ResourceKey), new CodePrimitiveExpression(fields.DefaultKey));
            else    exp =   new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(typeof(DBResourceExpressionBuilder)), "GetGlobalResourceObject", new CodePrimitiveExpression(fields.ClassKey), new CodePrimitiveExpression(fields.ResourceKey));

            return exp;
        }

        /// <summary>
        /// Format is [ClassKey,] ResourceKey [|DefaultValue]
        // if ResourceKey not found and no DefaultValue, throw
        /// </summary>
        public override object ParseExpression(string expression, Type propertyType, ExpressionBuilderContext context)
        {
            if ( ResourceTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder ParseExpression BEG ({0}, {1}, {2})", expression, propertyType, context),ResourceTraceSwitch.Sw.Info);
            
            if (string.IsNullOrEmpty(expression))
            {
                throw new ArgumentException(String.Format(Thread.CurrentThread.CurrentUICulture,Properties.Resources.Expression_TooFewParameters, expression));
            }

            
            string classKey                     =   string.Empty;
            string resourceKey                  =   string.Empty;
            string defaultKey                   =   string.Empty;
            
            // Format is [ClassKey,] ResourceKey [|DefaultValue]

            if ( expression.IndexOf(',') > -1 )
            {
                string[] expParams              =   expression.Split(new char[] { ',' },StringSplitOptions.RemoveEmptyEntries);
                int len                         =   expParams.Length;
                if ( len > 2 )
                {
                    throw new ArgumentException(String.Format(Thread.CurrentThread.CurrentUICulture, Properties.Resources.Expression_TooManyParameters, expression));
                }
                classKey                        =   expParams[0].Trim();
                resourceKey                     =   expParams[1].Trim();
            }
            else
            {
                classKey                        =   DefaultClassKey; // here take default resource
                resourceKey                     =   expression.Trim();
                defaultKey                      =   string.Empty;
            }
            if ( resourceKey.IndexOf('|') > -1 )
            {
                string[] expParams              =   resourceKey.Split(new char[] { '|' },StringSplitOptions.RemoveEmptyEntries);
                resourceKey                     =   expParams[0].Trim();
                defaultKey                      =   expParams[1].Trim();
            }

            if ( ResourceTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder ParseExpression classkey: {0}, resourceKey: {1}, defaultKey: {2}", classKey,resourceKey,defaultKey),ResourceTraceSwitch.Sw.Info);
            DBResourceExpressionFields fields   =   new DBResourceExpressionFields(classKey, resourceKey,defaultKey);

            DBResourceExpressionBuilder.EnsureResourceProviderFactory();
            IResourceProvider rp                =   DBResourceExpressionBuilder.s_resourceProviderFactory.CreateGlobalResourceProvider(fields.ClassKey);
            // Check minimal exists in invariant culture not necessarily current ui culture)
            object res                          =   null;
            try
            {
                res                          =   rp.GetObject(fields.ResourceKey, CultureInfo.InvariantCulture);
            }
            catch(Exception ex)
            {
                if ( ResourceTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder ParseExpression cached defaultKey: {0}, ex: {1}", defaultKey,ex),ResourceTraceSwitch.Sw.Info);
                if ( defaultKey == string.Empty )
                    throw;
            }
            if (res == null)
            {
                // if no default key, throw
                if ( defaultKey == string.Empty )
                    throw new ArgumentException(String.Format(Thread.CurrentThread.CurrentUICulture, Properties.Resources.RM_ResourceNotFound, fields.ResourceKey));
            }
            if ( ResourceTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]DBResourceExpressionBuilder ParseExpression END classkey: {0}, resourceKey: {1}, defaultKey: {2}", classKey,resourceKey,defaultKey),ResourceTraceSwitch.Sw.Info);
            return fields;
        }

        private static void EnsureResourceProviderFactory()
        {
            if (DBResourceExpressionBuilder.s_resourceProviderFactory == null)
            {
                DBResourceExpressionBuilder.s_resourceProviderFactory = new DBResourceProviderFactory();
            }
        }

        public override bool SupportsEvaluate
        {
            get
            {
                if ( ResourceTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine("[V]DBResourceExpressionBuilder SupportsEvaluate Called.",ResourceTraceSwitch.Sw.Info);
                return true;
            }
        }
    }

    public class DBResourceExpressionFields
    {
        private string m_classKey;
        private string m_resourceKey;
        private string m_defaultKey;
        public bool ExistResource   =   true;

        internal DBResourceExpressionFields(string classKey, string resourceKey,string defaultKey)
        {
            m_classKey     =   classKey;
            m_resourceKey  =   resourceKey;
            m_defaultKey   =   defaultKey;
        }

        public string ClassKey
        {
            get
            {
                return m_classKey;
            }
        }

        public string ResourceKey
        {
            get
            {
                return m_resourceKey;
            }
        }
        public string DefaultKey
        {
            get
            {
                return m_defaultKey;
            }
        }
    }
    
    public class ResourceRecord
    {
        private string m_resourceType;

        public string ResourceType
        {
            get { return m_resourceType; }
            set { m_resourceType = value; }
        }
        private string m_cultureCode;

        public string CultureCode
        {
            get { return m_cultureCode; }
            set { m_cultureCode = value; }
        }
        private string m_resourceKey;

        public string ResourceKey
        {
            get { return m_resourceKey; }
            set { m_resourceKey = value; }
        }
        private string m_resourceValue;

        public string ResourceValue
        {
            get { return m_resourceValue; }
            set { m_resourceValue = value; }
        }


    }
}